module Trivia (Trivia, nuevaT, keywordsT, preguntasT, participantesT, ganadoresT,
proxPreguntaParticipanteT, puntajeAcumuladoT, registrarJugadorT, desregistrarJugadorT,
procesarRespuestaT, usuariosEficientesT, posicionEnT, palabrasRecurrentesT)

where

import Tipos
import SMS
import Pregunta

data Trivia = CrearT [Keyword] [Pregunta] | Jugar Usuario Texto Trivia deriving (Show)

-- Testing --

triviaEj = Jugar 9876 "Sarala"(Jugar 123456 "Sarasa Grandes"(Jugar 123456 "Sarasa"(Jugar 007 "Sarasa Interesantes"(Jugar 007 "Sarasa Enormes"(Jugar 007 "Sarasa Grandes"(Jugar 007 "Sarasa"(Jugar 678 "Sarasa Espectaculares" (Jugar 91011 "Sarasa Espectaculares" (Jugar 91011 "Sarasa Oficialistas" (Jugar 678 "Sarasa Gordas" (Jugar 678 "Sarasa Oficialistas" (Jugar 91011 "Sarasa Espectaculares" (Jugar 678 "Sarasa Grandes" (Jugar 12345 "Sarasa Gordas" (Jugar 678 "Sarasa" (Jugar 91011 "Sarasa" (Jugar 12345 "Sarasa" (CrearT ["Sarasa","Sarala"] [(nuevaP "Como tiene las tetas tu vieja?" "Grandes" 1000), (nuevaP "Como tiene las tetas tu abuela?" "Enormes" 100), (nuevaP "Como tiene las tetas tu nuera?" "Interesantes" 10)]))))))))))))))))))
triviaEj2 = (Jugar 5 "Algo1 Berlin"(Jugar 5 "Algo1 No"(Jugar 5 "Chamuyo 4 "(Jugar 5 "Algo1"(Jugar 4 "Algo1"(Jugar 3 "Chamuyo Para mi si"(Jugar 3 "Algo1 15"(Jugar 3 "Algo1"(Jugar 2 "Chamuyo Muchas Boludeces"(Jugar 1 "Algo1 Boludeces"(Jugar 1 "Algo1 No"(Jugar 2 "Algo1 Si"(Jugar 1 "Chamuyo 4"(Jugar 2 "Chamuyo 25"(Jugar 1 "Algo1"(Jugar 2 "Chamuyo"(CrearT ["Chamuyo","Algo1"] [(nuevaP "2+2?" "4" 25),(nuevaP "Miento?" "No" 25),(nuevaP "Capital de Alemania?" "Berlin" 25),(nuevaP "Independencia?" "1816" 25)])))))))))))))))))
triviaEj3 = (Jugar 7 "Sarasa Magnificas"(
             Jugar 7 "Sarasa Campeon"(
             Jugar 7 "Sarasa Enormes"(
             Jugar 7 "Sarasa Grandes"(
             Jugar 8 "Sarasa Enormes" (
             Jugar 8 "Sarasa Grandes" (
             Jugar 8 "Sarasa" (
                        CrearT ["Sarasa","Sarala"] 
                               [(nuevaP "Como tiene las tetas tu vieja?" "Grandes" 1000), 
                                (nuevaP "Como tiene las tetas tu abuela?" "Enormes" 100), 
                                (nuevaP "Como tiene las tetas tu nuera?" "Interesantes" 10)]
            ))))))))

-- Fin testing --

-- Funciones generales -- 

nuevaT :: [Keyword] -> [Pregunta] -> Trivia
nuevaT keywords preguntas = CrearT keywords preguntas

keywordsT :: Trivia -> [Keyword]
keywordsT (CrearT keywords _) = keywords
keywordsT (Jugar _ _ trivia) = keywordsT trivia

preguntasT :: Trivia -> [Pregunta]
preguntasT (CrearT _ preguntas) = preguntas
preguntasT (Jugar _ _ trivia) = preguntasT trivia

participantesT :: Trivia -> [Usuario]
participantesT (CrearT _ _) = []
participantesT (Jugar usuario _ trivia) = sacarRepetidos
        (usuario : (participantesT trivia))

-- Fin funciones generales --

-- GanadoresT -- 

ganadoresT :: Trivia -> [Usuario]
ganadoresT (CrearT _ _) = []
ganadoresT (Jugar usuario texto trivia)
        | ganadoresTAux (Jugar usuario texto trivia) usuario =
                (ganadoresT trivia) ++ [usuario]
        | otherwise = ganadoresT trivia

ganadoresTAux :: Trivia -> Usuario -> Bool
ganadoresTAux (CrearT _ _) _ = False
ganadoresTAux trivia usuarioCandidato =
        (respuestasEnviadas trivia usuarioCandidato == length (preguntasT trivia) + 1)

respuestasEnviadas :: Trivia -> Usuario -> Int
respuestasEnviadas (CrearT _ _) _ = 0
respuestasEnviadas (Jugar usuario _ trivia) usuarioCandidato
        | usuario == usuarioCandidato = 1 + respuestasEnviadas trivia usuarioCandidato
        | otherwise = respuestasEnviadas trivia usuarioCandidato

-- Fin GanadoresT-- 

proxPreguntaParticipanteT :: Trivia -> Usuario -> Pregunta
proxPreguntaParticipanteT trivia usuario = preguntasT trivia !!
        ((respuestasEnviadas trivia usuario)-1)

-- PuntajeAcumuladoT -- 

puntajeAcumuladoT :: Trivia -> Usuario -> Puntaje
puntajeAcumuladoT trivia usuario = calcularPuntaje (preguntasT trivia)
        (tail (mensajesDe trivia usuario))

calcularPuntaje :: [Pregunta] -> [Texto] -> Puntaje
calcularPuntaje [] _ = 0
calcularPuntaje _ [] = 0
calcularPuntaje (x:xs) (y:ys) | rtaCorrectaP x == (sacarPalabra y) =
        (puntajeP x) + (calcularPuntaje xs ys)
                              | otherwise = calcularPuntaje xs ys
                     
mensajesDe :: Trivia -> Usuario -> [Texto]
mensajesDe (CrearT _ _) _ = []
mensajesDe (Jugar usuario texto trivia) usuarioSelec | usuario == usuarioSelec =
        (mensajesDe trivia usuarioSelec) ++ [texto]
                                                     | otherwise =
        mensajesDe trivia usuarioSelec 

-- Fin PuntajeAcumuladoT -- 

-- registrarJugadorT -- 

registrarJugadorT :: Trivia -> Usuario -> Keyword -> (Trivia,SMS)
registrarJugadorT trivia usuario keyword = ((Jugar usuario keyword trivia), 
        nuevoSMS usuario ("Hola, tenes 0 puntos. " ++
                primeraPregunta trivia usuario keyword))

primeraPregunta :: Trivia -> Usuario -> Keyword -> Texto
primeraPregunta trivia usuario keyword = 
        textoP (proxPreguntaParticipanteT(Jugar usuario keyword trivia) usuario)

-- Fin registrarJugadorT -- 

-- desregistrarJugadorT -- 

desregistrarJugadorT:: Trivia -> Usuario -> Trivia
desregistrarJugadorT (CrearT keyword pregunta) _ = (CrearT keyword pregunta)
desregistrarJugadorT (Jugar usuarioT texto trivia) usuario | usuario == usuarioT =
        desregistrarJugadorT trivia usuario
                                                           | otherwise =
        (Jugar usuarioT texto (desregistrarJugadorT trivia usuario))
                                                                                                           
-- Fin desregistrarJugadorT -- 

-- procesarRespuestaT -- 

procesarRespuestaT :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
procesarRespuestaT trivia usuario texto
        | esGanador trivia usuario = respuestaGanador trivia usuario
        | esUltima trivia usuario = respuestaUltima trivia usuario texto
        | esCorrecta texto (proxPreguntaParticipanteT trivia usuario) =
                respuestaDeCorrecta trivia usuario texto
        | otherwise = respuestaDeIncorrecta trivia usuario texto 

respuestaGanador :: Trivia -> Usuario -> (Trivia,SMS)
respuestaGanador trivia usuario = (trivia, nuevoSMS usuario
        "Gracias por seguir pagando, pero el juego termino.")

respuestaUltima :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
respuestaUltima trivia usuario texto = (Jugar usuario texto trivia, nuevoSMS usuario
        (textoUltima trivia usuario texto))

textoUltima :: Trivia -> Usuario -> Texto -> Texto
textoUltima trivia usuario texto = "Has respondido todas las preguntas. " ++
        (tusPuntos usuario texto trivia)

respuestaDeCorrecta :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
respuestaDeCorrecta trivia usuario texto = ((Jugar usuario texto trivia),
        (nuevoSMS usuario ("Bien! " ++ textoDeRespuestaCI trivia usuario texto)))

respuestaDeIncorrecta :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
respuestaDeIncorrecta trivia usuario texto = ((Jugar usuario texto trivia),
        (nuevoSMS usuario ("Mal! " ++ textoDeRespuestaCI trivia usuario texto)))

textoDeRespuestaCI :: Trivia -> Usuario -> Texto -> Texto
textoDeRespuestaCI trivia usuario texto = (tusPuntos usuario texto trivia) ++ " " ++
        textoP(proxPreguntaParticipanteT (Jugar usuario texto trivia) usuario)

esGanador :: Trivia -> Usuario -> Bool
esGanador (CrearT _ _) _ = False
esGanador trivia usuarioCandidato =
        (respuestasEnviadas trivia usuarioCandidato >= length (preguntasT trivia) + 1)

esCorrecta :: Texto -> Pregunta -> Bool
esCorrecta texto proximaPregunta =
        (palabras (sacarPalabra texto)) == (palabras (rtaCorrectaP proximaPregunta))

esUltima :: Trivia -> Usuario -> Bool
esUltima trivia usuario = (textoP (proxPreguntaParticipanteT trivia usuario) ==
        textoP ((preguntasT trivia) !! ((length (preguntasT trivia))-1)))

tusPuntos :: Usuario -> String -> Trivia -> String
tusPuntos usuario texto trivia = "Tenes " ++
        intToString (puntajeAcumuladoT (Jugar usuario texto trivia) usuario) ++ " ptos."

-- Fin procesarRespuestaT -- 

-- UsuariosEficientesT -- 

usuariosEficientesT :: Trivia -> [Usuario]
usuariosEficientesT trivia = losDeMenosParticipaciones trivia
        (losDeMaximoPuntaje trivia (participantesT trivia))

losDeMaximoPuntaje :: Trivia -> [Usuario] -> [Usuario]
losDeMaximoPuntaje _ [] = []
losDeMaximoPuntaje trivia (x:xs)
        | (puntajeAcumuladoT trivia x) == (maximoPuntaje trivia) =
                x : (losDeMaximoPuntaje trivia xs)
        | otherwise = losDeMaximoPuntaje trivia xs
                                 
maximoPuntaje :: Trivia -> Int
maximoPuntaje trivia = maximo (puntajeDeTodos trivia (participantesT trivia))

puntajeDeTodos :: Trivia -> [Usuario] -> [Int]
puntajeDeTodos _ [] = []
puntajeDeTodos trivia (x:xs) = (puntajeAcumuladoT trivia x):(puntajeDeTodos trivia xs)

maximo :: [Int] -> Int
maximo [x] = x
maximo (x:xs) | esMayorOIgualQueTodos x xs = x
              | otherwise = maximo xs
              
esMayorOIgualQueTodos :: Int -> [Int] -> Bool
esMayorOIgualQueTodos x [] = True
esMayorOIgualQueTodos x (y:xs) = (x >= y) && (esMayorOIgualQueTodos x xs)

losDeMenosParticipaciones :: Trivia -> [Usuario] -> [Usuario]
losDeMenosParticipaciones trivia [] = []
losDeMenosParticipaciones trivia (x:xs)
        | respuestasEnviadas trivia x == minimo (participacionesDeTodos trivia (x:xs)) =
                x:(losDeMenosParticipaciones trivia xs)
        | otherwise = losDeMenosParticipaciones trivia xs
                                        
participacionesDeTodos :: Trivia -> [Usuario] -> [Int]
participacionesDeTodos _ [] = []
participacionesDeTodos trivia (x:xs) =
        (respuestasEnviadas trivia x) : (participacionesDeTodos trivia xs)                                        
                                        
minimo :: [Int] -> Int
minimo [x] = x
minimo (x:xs) |esMenorOIgualQueTodos x xs = x
              |otherwise = minimo xs
                          
esMenorOIgualQueTodos :: Int -> [Int] -> Bool
esMenorOIgualQueTodos x [] = True
esMenorOIgualQueTodos x (y:xs) = (x <= y) && (esMenorOIgualQueTodos x xs)

-- Fin UsuariosEficientesT -- 

-- posicionEnT --  

posicionEnT :: Trivia -> Usuario -> Int
posicionEnT trivia usuario | usuario `elem` (ganadoresT trivia) =
        indice usuario (ganadoresT trivia)
                           | otherwise =
        length (ganadoresT trivia) +
        length (participantesConMasPuntosQue trivia usuario (participantesT trivia))

participantesConMasPuntosQue :: Trivia -> Usuario -> [Usuario] -> [Usuario]
participantesConMasPuntosQue _ _ [] = []
participantesConMasPuntosQue trivia usuario (x:xs)
        | noGanadorConMasPuntaje trivia usuario x =
                x : (participantesConMasPuntosQue trivia usuario xs)
        | otherwise = participantesConMasPuntosQue trivia usuario xs

noGanadorConMasPuntaje :: Trivia -> Usuario -> Usuario -> Bool
noGanadorConMasPuntaje trivia usuario noG = not(noG `elem` (ganadoresT trivia)) &&
        (puntajeAcumuladoT trivia noG) > (puntajeAcumuladoT trivia usuario)
               
indice:: Eq a => a -> [a] -> Int
indice u (x:xs) | u==x = 0
                | otherwise = 1 + indice u xs

-- Fin posicionEnT -- 

-- palabrasRecurrentesT --

palabrasRecurrentesT :: Trivia -> Int -> [String]
palabrasRecurrentesT trivia n = sacarRepetidos(lasMasRecurrentes 
        ( masLargasQueNDeTrivia trivia n ) ( masLargasQueNDeTrivia trivia n ))

lasMasRecurrentes :: [String] -> [String] -> [String]
lasMasRecurrentes [] _ = []  
lasMasRecurrentes (x:xs) ys 
        | (apareceMasQueTodosLosDemas x ys ys) = (x : (lasMasRecurrentes xs ys))
        | otherwise = lasMasRecurrentes xs ys
                                                 
apareceMasQueTodosLosDemas :: Eq a => a ->[a] ->[a] -> Bool
apareceMasQueTodosLosDemas _ [] _ = True
apareceMasQueTodosLosDemas a (x:xs) ys = 
        (cantApariciones a ys >= cantApariciones x ys) 
        && apareceMasQueTodosLosDemas a xs ys
                                                                                  
cantApariciones:: Eq a => a -> [a] -> Int
cantApariciones _ [] = 0
cantApariciones x (y:ys) |x==y = 1 + (cantApariciones x ys)
                         |otherwise = cantApariciones x ys 

masLargasQueNDeTrivia :: Trivia -> Int -> [String]               
masLargasQueNDeTrivia trivia n = 
        masLargasQueN (palabrasDePregConRes (preguntasT trivia)) n

masLargasQueN :: [String] -> Int -> [String]
masLargasQueN [] _ = []
masLargasQueN (x:xs) n | length x < n = masLargasQueN xs n
                       | otherwise = x: (masLargasQueN xs n)

palabrasDePregConRes :: [Pregunta] -> [String]
palabrasDePregConRes [] = []
palabrasDePregConRes (p:ps) = palabras(textoP p) ++ palabras(rtaCorrectaP p) 
        ++ palabrasDePregConRes ps

-- Fin palabras recurrentes --
